require 'event_editor/commands_dialog'
require 'event_editor/commands/condition'
require 'lib'
module EventEditor
  class CommandPanel < Gtk::VBox
    HEADER = "<b>◆</b>"
    MARGIN = "     "
    
    Node = Struct.new(:command, :parent, :children, :deletable, :view_iter, :depth)
    #@@blank_icon = Gdk::Pixbuf.new("icon/command/blank.xpm")
    def initialize(base, event_model)
      @node_root = Node.new([], nil, [], false, nil, 0)
    
      super()
      @base = base
      self.set_border_width(5)
      @event_model = event_model
      @command_model = Gtk::ListStore.new(String, Node)
      @command_box = Gtk::TreeView.new(@command_model)
      sw = Gtk::ScrolledWindow.new
      sw.add(@command_box)
      @command_box.enable_search = false
      @command_box.headers_visible = false
      @command_box.selection.mode = Gtk::SELECTION_MULTIPLE
      # Tree View Events    
      
      renderer = Gtk::CellRendererText.new
      column = Gtk::TreeViewColumn.new("", renderer, { :markup => 0 })
      @command_box.append_column(column)
      
      # Events
      @command_box.signal_connect('row-activated') do |view, path, column|
        # get selected nodes
        arr = []
        @command_box.selection.selected_each do |model, path, iter|
          arr << self.get_node(iter)
        end
        return if arr.empty?
        
        # sort by depth
        arr.sort!{|b, a| b.depth <=> a.depth}
        
        depth = arr.first.depth
        if arr.first.deletable && arr.select{|item| item.depth == depth}.length == 1
          show_commands_dialog(arr.first.view_iter, arr.first.command)
        end
        
        # go to edit window if not-multiple nodes are selected
      end
      
      stopper = false
      @command_box.selection.signal_connect('changed') do
        unless stopper
          stopper = true
          
          if self.get_selected_node_count == 1
            arr = [self.get_single_selected_node]
          else
            arr = self.selected_min_depth_nodes
          end
          @command_box.selection.unselect_all
          arr.each do |node|
            @command_box.selection.select_iter(node.view_iter)
            self.select_children(@command_box.selection, node)
          end
          stopper = false
        end
      end
      
      @command_box.signal_connect("button-press-event") do |item, event|        
        if event.button  == 3
         self.show_commands_dialog
        end 
      end
      
      @command_box.signal_connect('key-press-event') do |widget, event|
        case event.keyval
        when 100, 65535 # delete
          self.delete_selected_items
        when 99  # copy
          self.copy
        when 118  # paste
          self.paste
        when 120 # cut
          self.cut
        end
      end
     
      self.add(sw)
    end
    
    def get_single_selected_node
      @command_box.selection.selected_each do |model, path, iter| 
        return self.get_node(iter)
      end
      return nil
    end
    
    def get_selected_node_count
      i = 0
      @command_box.selection.selected_each do |model, path, iter| 
        i += 1
      end
      return i
    end
    
    def selected_min_depth_nodes
      arr = []
      min_depth = 9999999
      @command_box.selection.selected_each do |model, path, iter|
        node = self.get_node(iter)
        arr << node if node.deletable
        min_depth = [node.depth, min_depth].min
      end
      arr = arr.select {|node| node.depth == min_depth}
      return arr
    end
    
    def select_children(selection, node)
      return unless node
      node.children.each do |child|
        next unless child
        selection.select_iter(child.view_iter)
        self.select_children(selection, child)
      end
    end

    def delete_selected_items
      remove_list = []
 
      @command_box.selection.selected_each do |model, path, iter|
        node = self.get_node(iter)
        next unless node.deletable && node.command
        
        remove_list << node
        remove_list += self.get_remove_children(@command_model, node)
      end
      
      arr = []
      remove_list.each do |node|
        arr << node.view_iter
      end
      arr.uniq!

      remove_list = []
      arr.each do |iter|
        remove_list << self.get_node(iter)
      end
      remove_list.compact!
      remove_list.sort!{|b, a| b.depth <=> a.depth}
      remove_list.each do |node|
        self.remove_node(node)
      end
    end
    
    def get_remove_children(model, node)
      return [] unless node
      arr = []
      node.children.each do |child|
        next unless child
        child.parent = nil
        arr += self.get_remove_children(model, child)
        arr << child
      end
      return arr
    end
    
    def show_commands_dialog(iter = nil, edit_command = [])
      CommandsDialog.show(@base, @event_model, edit_command) do |command|
        self.add_item(iter, command)
      end
    end

    # def get_depth(node)
      # i = 0
      # parent = node.parent
      # while(parent)
        # parent = parent.parent
        # i += 1
      # end
      # return i
    # end
    
    def get_margin(depth)
      #i = self.get_depth(node)
      i =depth
      margin = ""
      i.times do
        margin += MARGIN
      end
      return margin
    end
    
    def get_command(node)
      if node.command[0] == 'if'
        i = 0
        node.children.each do |n|
          if n.deletable
            node.command[3][i] << self.get_command(n)
          end
          i = 1 if n.command[0] == 'else'
        end
      end
      return node.command
    end
    
    def commands
      commands = []
      iter = @command_model.iter_first
      begin
        node = self.get_node(iter)
        commands << node.command if node.command
      end while iter.next!
      return commands
    end
    
    def cut
      self.copy
      self.delete_selected_items
    end
    
    def copy
      commands = []
      @command_box.selection.selected_each do |model, path, iter|
        node = self.get_node(iter)
        commands << node.command if node.command
      end
      # nodes = self.selected_min_depth_nodes
      # commands = []
      # nodes.each do |node|
        # commands << self.get_command(node)
      # end
      commands.each do |command|
        #p command
      end

      $buffer['event_command'] = commands
    end
    
    def paste_commands(selected_node, commands)
      return unless selected_node
      node = selected_node
      depth = selected_node.depth
      parent = selected_node.parent
      commands.each do |command|
        iter = @command_model.insert_before(selected_node.view_iter)

        deletable = true
        case command[0]
        when 'else', 'end'
          margin = self.get_margin(parent.depth)
          iter[0] = self.get_command_name(command[0], command, margin)
        else
          margin = self.get_margin(depth)
          iter[0] = margin + HEADER + self.get_command_name(command[0], command, margin)
        end

        node = self.add_node(command, parent, deletable, iter, depth)
        
        case command[0]
        when 'if'
          depth += 1
          parent = node
        when 'else'
        when 'end'
          depth -= 1
          parent = parent.parent
        end
      end
    end
    
    def paste
      self.paste_commands(self.get_single_selected_node, $buffer['event_command'])
    end

    def add_item(edit_iter, command)
      # Select Node & Iter
      selected = nil
      if edit_iter
        edit_node = self.get_node(edit_iter)
        selected = edit_iter
        selected_node = self.get_node(selected)
        
      else
        selected_node = self.get_single_selected_node
        @command_box.selection.selected_each {|model, path, iter| selected = iter; break;}
        selected = @command_model.iter_first unless selected
      end
      
      # Get Text
      if selected
        margin = self.get_margin(selected_node.depth)
        s = ''
        icon = nil

        # Generate new Iter and Node
        s = self.get_command_name(command[0], command, margin)

        if edit_iter
          edit_iter[0] = margin + HEADER + s
          edit_node.command = command
        else
          iter = @command_model.insert_before(selected)
          iter[0] = margin + HEADER + s
          new_node = self.add_node(command, selected_node.parent, true, iter, selected_node.depth)
          self.add_if(margin, command, new_node)
        end
      end
    end

    def get_command_name(type, command, margin)
        case type
          when 'if'
            s = Commands::Condition.command_to_s(@event_model, command, margin)
          when 'else'
            s = margin + '<span color="blue"><b>:else</b></span>'
          when 'end'
            s = margin + '<span color="blue"><b>:end</b></span>'
          else
            s = Lib.fileNameToClass('event_editor/commands/', 'EventEditor::Commands::', type).command_to_s(@event_model, command, margin)
        end
        return s
    end
    
    # Add if Statement  
    def add_if(margin, command, node)
      if command[0] == 'if'
        n = node
        n = self.add_else(margin, n, node) if command[1]
        self.add_end(margin, n, node)
      end
    end

    def add_else(margin, node, parent)
      p nil
      t = @command_model.insert_after(node.view_iter)
      t[0] = self.get_command_name('else', [], margin)#margin + '<span color="blue"><b>:else</b></span>'
      return self.add_node(['else'], parent, false, t, parent.depth + 1)
    end
    
    def add_end(margin, node, parent)
      t = @command_model.insert_after(node.view_iter)
      t[0] = self.get_command_name('end', [], margin)#margin + '<span color="blue"><b>:end</b></span>'
      return self.add_node(['end'], parent, false, t, parent.depth + 1)
    end

    def add_node(command, parent, deletable, iter, depth)
      n = Node.new(command, parent, [], deletable, iter, depth)
      parent.children << n if parent
      
      iter[1] = n
      return n
    end
    
    def get_node(iter)
      return iter[1]
    end
    
    def remove_node(node)
      node.parent.children.delete(node) if node.parent
      @command_model.remove(node.view_iter)
    end
    
    def refresh
      iter = @command_box.selection.iter_first
      begin
        arr << iter[1]
      end while iter.next!
    end
    
    def load(commands)
    
      @command_model.clear
      iter = @command_model.append
      iter[0] = HEADER

      @node_root = Node.new([], nil, [], false, nil, 0)
      node = self.add_node(nil, @node_root, false, iter, 0)
      
      @command_box.selection.select_iter(iter)
      
      self.paste_commands(node, commands)
    end
  end
end